package com.basic.quartz.util;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.text.MessageFormat;
import java.util.Date;

import com.basic.common.utils.DateUtils;
import com.basic.common.utils.EmailService;
import com.basic.quartz.domain.SysJob;
import com.basic.quartz.domain.SysJobLog;
import io.netty.util.Timeout;
import io.netty.util.TimerTask;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.basic.common.constant.Constants;
import com.basic.common.constant.ScheduleConstants;
import com.basic.common.utils.ExceptionUtil;
import com.basic.common.utils.StringUtils;
import com.basic.common.utils.bean.BeanUtils;
import com.basic.common.utils.spring.SpringUtils;
import com.basic.quartz.service.ISysJobLogService;

import javax.annotation.Resource;

/**
 * 抽象quartz调用
 *
 * @author zhaoxy_jn@163.com
 */
public abstract class AbstractQuartzJob implements Job
{
    private static final Logger log = LoggerFactory.getLogger(AbstractQuartzJob.class);

    @Resource
    private EmailService emailService;

    /**
     * 线程本地变量
     */
    private static ThreadLocal<Date> threadLocal = new ThreadLocal<>();

    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException
    {
        SysJob sysJob = new SysJob();
        BeanUtils.copyBeanProp(sysJob, context.getMergedJobDataMap().get(ScheduleConstants.TASK_PROPERTIES));
        try
        {
            before(context, sysJob);
            if (sysJob != null)
            {
                doExecute(context, sysJob);
            }
            after(context, sysJob, null);
        }
        catch (Exception e)
        {
            log.error("任务执行异常  - ：", e);
            // 发送错误信息邮件
            sendEmail(sysJob.getJobName(),sysJob.getInvokeTarget());
            // 执行后置方法
            after(context, sysJob, e);
        }
    }

    /**
     * 执行前
     *
     * @param context 工作执行上下文对象
     * @param sysJob 系统计划任务
     */
    protected void before(JobExecutionContext context, SysJob sysJob)
    {
        threadLocal.set(new Date());
    }

    /**
     * 执行后
     *
     * @param context 工作执行上下文对象
     * @param sysJob 系统计划任务
     */
    protected void after(JobExecutionContext context, SysJob sysJob, Exception e)
    {
        Date startTime = threadLocal.get();
        threadLocal.remove();

        final SysJobLog sysJobLog = new SysJobLog();
        sysJobLog.setJobName(sysJob.getJobName());
        sysJobLog.setJobGroup(sysJob.getJobGroup());
        sysJobLog.setInvokeTarget(sysJob.getInvokeTarget());
        sysJobLog.setStartTime(startTime);
        sysJobLog.setStopTime(new Date());
        long runMs = sysJobLog.getStopTime().getTime() - sysJobLog.getStartTime().getTime();
        sysJobLog.setJobMessage(sysJobLog.getJobName() + " 总共耗时：" + runMs + "毫秒");
        if (e != null)
        {
            sysJobLog.setStatus(Constants.FAIL);
            String errorMsg = StringUtils.substring(ExceptionUtil.getExceptionMessage(e), 0, 2000);
            sysJobLog.setExceptionInfo(errorMsg);
        }
        else
        {
            sysJobLog.setStatus(Constants.SUCCESS);
        }

        // 写入数据库当中
        SpringUtils.getBean(ISysJobLogService.class).addJobLog(sysJobLog);


    }

    /**
     * 执行方法，由子类重载
     *
     * @param context 工作执行上下文对象
     * @param sysJob 系统计划任务
     * @throws Exception 执行过程中的异常
     */
    protected abstract void doExecute(JobExecutionContext context, SysJob sysJob) throws Exception;

    /**
     * 定时任务出现错误后，发送邮件
     */
    private void sendEmail(String jobName,String invokeTarget) {
        new TimerTask(){

            @Override
            public void run(Timeout timeout) throws Exception {

                // 加载邮件html模板
                String fileName = "framework/task_notice_html.html";
                InputStream inputStream = ClassLoader.getSystemResourceAsStream(fileName);
                if (inputStream == null) {
                    log.error("无法加载文件: {0}", fileName);
                    return;
                }

                try (BufferedReader fileReader = new BufferedReader(new InputStreamReader(inputStream))) {
                    StringBuilder buffer = new StringBuilder();
                    String line;
                    while ((line = fileReader.readLine()) != null) {
                        buffer.append(line);
                    }

                    String contentText = "<p>任务名称：" + escapeHtml(jobName) + "</p><p>目标字符串：" + escapeHtml(invokeTarget) + "</p>";

                    // 填充html模板中的两个参数
                    String htmlText = MessageFormat.format(buffer.toString(),"定时任务失败通知", "以下是定时任务执行失败信息，请查看.", contentText, DateUtils.getTime());

                    emailService.sendGeneralEmail("定时任务失败", htmlText, "zhaoxy_jn@163.com");
                } catch (IOException e) {
                    log.error("读取文件失败，fileName: {0}，错误信息-> {}", fileName, e);
                } catch (Exception e) {
                    // 捕获其他非预期异常
                    log.error("发送任务失败通知时发生意外错误", e);
                }
            }
        };

    }

    private static String escapeHtml(String input) {
        // 简单的HTML转义实现，实际应用中可能需要更复杂的逻辑
        return input.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;");
    }
}
